"""
This module is responsible for handling connections.
A client is a wrapper around pants.Connection, and is the basic socket that each user will have.
"""
import logging
from pants import Stream
import utils
import player
from world import world
from constants import constate, mud
logger = logging.getLogger(__name__)

class client(Stream):
    """
    The client class wraps pants.Connection.
    It is the basic socket that each user has access to.
    """
    def __init__(self, *args, **kwargs):
        """
        Passes the arguments to the parent's constructor and initializes the client class.
        """
        #we set up our state table.
        self.states = {constate.name:self.do_name,
        constate.password:self.do_password,
        constate.newname:self.do_newname,
        constate.newpass:self.do_newpass,
        constate.verpass:self.do_verpass,
        constate.game:self.do_game,
        255:self.do_error}
        Stream.__init__(self, *args, **kwargs)
        #we set instance variables
        self.state = constate.new
        self.handlers = []

    def writelines(self, lines):
        """
        Writes the lines passed in.
        Arguments: a list or any iterable collection of lines to write.
        """
        for line in lines:
            self.writeline(line)
    def writeline(self, line):
        """
        Writes the specified line to the socket, appending newline.
        Arguments:
        The line to write.
        """
        self.write(line+"\r\n")

    def showNameRequirements(self):
        """
        Writes out all the requirements for usernames.
        """
        self.writeline("Before you can begin playing, you will need to choose a username.")
        self.writeline("This name is how you will be identified by other players.")
        self.writeline("Names must fit the theme of %s, and be between %d and %d characters." %(mud.name, mud.minname, mud.maxname))
        self.writeline("Names also must only contain only letters between A and Z, and must not contain any punctuation, numbers or spaces.")
        self.writeline("What name would you like?")
    def showPasswordRequirements(self):
        """
        Writes the requirements for the user's password.
        """
        self.writeline("A good password contains at least one punctuation character, one uppercase character and one number.")
        self.writeline("While we do not enforce password strength, we do require that passwords are between %d and %d characters in length." %(mud.minpass, mud.maxpass))

    def on_connect(self, *args):
        """
        Overloaded from the user socket.
        Called when a connection is received; we print the line and set the state.
        """
        self.writelines(world.banner)
        self.writeline("Please enter your username, or type new for a new account.")
        self.state = constate.name
        
    def on_read(self, data):
        """
        Overloaded from the base connection.
        Determines the state of the connection and handles the data based on the state table.
        """
        callable = self.states.get(self.state, self.states[255])
        callable(data.strip())

    def do_name(self, line):
        if line == "new":
            self.writeline("New character, welcome!")
            self.showNameRequirements()
            self.writeline("What name would you like?")
            self.state = constate.newname
            return
            
        if not utils.isValidUser(line):
            self.writeline("That is an invalid username.")
            self.writeline("What is your name?")
            return
        else:
            self.name = line
            self.writeline("What is your password?")
            self.state = constate.password

    def do_password(self, line):
        if not utils.isValidPassword(line):
            self.writeline("Invalid password.")
            self.writeline("Please enter your password.")
            return
        else:
            self.password = line
            self.login()

    def do_newname(self, line):
        if not utils.isValidUser(line):
            self.showNameRequirements()
            self.writeline("What name would you like?")
            return

        self.name = line
        self.writeline("Now that you have chosen a name, it is time to choose a password.")
        self.showPasswordRequirements()
        self.writeline("What is your password?")
        self.state = constate.newpass

    def do_newpass(self, line):
        if not utils.isValidPassword(line):
            self.writeline("Invalid password.")
            self.showPasswordRequirements()
            self.writeline("What is your password?")
            return

        self.writeline("Please re-enter your password.")
        self.password = line
        self.state = constate.verpass

    def do_verpass(self, line):
        if line == self.password:
            self.writeline("Your character is now created!")
            self.create()
            self.login()
            del self.password
            del self.name
        else:
            self.writeline("Your passwords did not match. Please try again.")
            self.showPasswordRequirements()
            self.state = constate.newpass

    def create(self):
        player.create(self)
        self.state = constate.game

    def login(self):
        try:
            player.login(self)
            self.state = constate.game
        except ValueError as e:
            self.writeline(e.message)
            self.writeline("Please enter your username, or type new for a new account.")
            self.state = constate.name

    def do_error(self, data):
        logger.error("Invalid state.")

    def do_game(self, line):
        world.handleCommand(self.player, line)
